/* @author Michael Antemann
 *  @created on 29.10.2008 
 *  Steuert das Spiel
 *  updated on 18.11.08 totally worked over
 *  Alles auf englisch umbenannt! die 
 *  fassaden klasse an das neue array vom gui angepasst
 *  steine nehmen angepasst, das keine eigenen genommen werden 
 *  06.12.2008 . 
 *  	Move methoden die was tun in rules ausgelagert.
 *  	move() überlagert mit move(int)
 *  	move(int) prüft regeln und gibt gewählte mulde an Rules.makemove weiter am laufen,
 *   
 *   für ki beteiligung 
 *  	move() -:> ermittelt int wert über die ki move methode und gibt diesen dann an die norme move(int)
 *  	der ki zug wird normal behandelt wie der vom spieler auch
 *   
 *   Änderungen 09.12.2008 Michael Antemann:
 *   run() Methode entfernt
 *   nicht benutzte variablen werte variabeln imports entfernt
 *  
 *  Schleife für move hinzugefügt. keine rekursion mehr!
 *  parameter von ki.move(int[], int[] ,int ) korrigiert. bekam falsches feeld für B beachte problem eintrag bei todo
 *  
 *  wenn eine ki das spiel beginnt lös startGame dies am schluss aus.
 */

package de.fhhannover.inform.wari.grp8.spiel;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Observable;
import java.io.File;
import de.fhhannover.inform.studienklassen.semester3.GeneralStatics;
import de.fhhannover.inform.wari.strategy.MoveStrategy;

public class GameFlow extends Observable {
	private boolean logging = true;
	private double version = 1.1;
	Board mBoard = new Board(0);
	private long lastThinktime = 0;
	private int mBeginning = -1;
	private int mCount = -1;
	private int illigalCount = 0;
	private Rules ruler;
	// allgemein gueltig_:>
	String del = File.separator;
	// private String mStrategyPathA=
	// "bin"+del+"strategies"+del+"de"+del+"fhhannover"+del+"inform"+del+"wari"+del+"grp8"+del+"StrategyG8.class";
	// private String mStrategyPathB=
	// "bin"+del+"strategies"+del+"de"+del+"fhhannover"+del+"inform"+del+"wari"+del+"grp8"+del+"KiMitListe.class";
	private int mStrategyPathA = 0;
	private int mStrategyPathB = 0;

	private MoveStrategy mKiA = (MoveStrategy) StrategyHandler
			.getStrategyHandler().getStrategyByPathIndex(mStrategyPathA);
	private MoveStrategy mKiB = (MoveStrategy) StrategyHandler
			.getStrategyHandler().getStrategyByPathIndex(mStrategyPathB);
	private MoveStrategy emergency = (MoveStrategy) StrategyHandler
			.getStrategyHandler().getStrategyByPathIndex(0);
	Logger mylog;
	StringBuffer mLogging = new StringBuffer("");

	public GameFlow() {

		super();
		mylog = new Logger();
		mBoard = new Board(0);
		/* setze initialisierungs werte */
		mBoard.setNameA("Unten");
		mBoard.setNameB("Oben");
		/* mBoard.setNameB(mKiB.getStrategyName()); */
	}

	public void startGame(String nA, String nB, boolean tA, boolean tB,
			boolean starter, int denkzeit) {

		mBoard.initialisation(4, starter, tA, tB, nA, nB);
		mBoard.setThinkingTime(denkzeit);
		mLogging = new StringBuffer(""); // neuen Buffer erzeugen
		// guter test für zwangszug
		/*
		 * int[] a= {0,0,0,1,2,1}; int[] b= {1,0,0,0,0,0}; mBoard.setPitsA(a);
		 * mBoard.setPitsB(b);
		 */

		/*
		 * //Test unentschieden int[] a= {1,0,0,0,0,1}; int[] b= {1,0,0,0,0,1};
		 * mBoard.setPitsA(a); mBoard.setPitsB(b);
		 */
		/*
		 * //Test int[] a= {0,0,0,0,0,0}; int[] b= {1,0,0,0,1,0};
		 * mBoard.setPitsA(a); mBoard.setPitsB(b);
		 */
		/*
		 * int[] a= {2,2,2,2,2,2}; int[] b= {2,2,2,2,2,2}; mBoard.setPitsA(a);
		 * mBoard.setPitsB(b); mBoard.addWinPitA(23); mBoard.addWinPitB(23);
		 */
		/*
		 * // zyklus test int[] a= {1,0,0,0,0,0}; int[] b= {1,0,0,0,0,0};
		 * mBoard.setPitsA(a); mBoard.setPitsB(b);
		 */
		ruler = new Rules(mBoard, this);
		mBoard.setStillrunning(true);

		kiMode();

		// move(); //move fuer ki

		// System.out.println(mBoard.toFString());
		shouldUpdate("Das Spiel kann begonnen werden!");
		if (mBoard.getType(mBoard.getWhoseTurn())) {
			move(-1);
		}
	}

	public void endgame() {
		// System.out.println("Das Spiel wird Beendet");
		// Test, der gui wird geschlossen, das brett und der fluss existieren
		// aber ncoh
		// aufräum arbeiten log // maybe log in datei sichern usw // ki killen
		if (logging) {
			mLogging.append("Programm wird beendet!");
			mylog.writeIntoFile(mLogging.toString());// Schreibe in Logdatei
		}
		// System.out.println(mBoard.toString());
		System.exit(0);
	}

	private void kiMode() {

		mKiA = (MoveStrategy) StrategyHandler.getStrategyHandler()
				.getStrategyByPathIndex(mStrategyPathA);
		if (mKiA == null) {
			mKiA = (MoveStrategy) StrategyHandler.getStrategyHandler()
					.getStrategyByPathIndex(0);
		}

		mKiB = (MoveStrategy) StrategyHandler.getStrategyHandler()
				.getStrategyByPathIndex(mStrategyPathB);
		if (mKiB == null) {
			mKiB = (MoveStrategy) StrategyHandler.getStrategyHandler()
					.getStrategyByPathIndex(0);
		}

	}

	private void error(String s) {
		mLogging.append("Fehler ist aufgetreten: " + s);
		mylog.writeIntoFile(mLogging.toString());// Schreibe in Logdatei
		System.exit(0);
	}

	// controller methode für menschen und ki!
	public int move(int in) {

		while (mBoard.isStillrunning()) {
			if (mBoard.getType(mBoard.getWhoseTurn())) {
				in = kiMove(mBoard.getWhoseTurn());
			}
			if (mBoard.isStillrunning()) {
				int muldenanzahl = mBoard.getPit(in);
				mBeginning = in;
				mCount = muldenanzahl;
				if (ruler.preCheck(in)) {
					int success = -1;
					success = ruler.makeMove(in);

					if (success == -1) {
						this
								.error("Beim ausführen des Zuges trat ein Fehler auf");
					}
					ruler.postCheck();
					// ++++++++ Schreibe Züge in den Puffer +++++++++++
					if (logging) {
						mLogging.append(this.toLogString(mBoard.getWhoseTurn(),
								in, muldenanzahl)
								+ "\r\n");
						mLogging.append((mBoard.toFString()));// Schreibe in
						// Logdatei
					}
					if (!mBoard.isStillrunning()) {
						mLogging.append("Spiel zu Ende: Sieger: "
								+ ruler.siegerString() + "\r\n");
						mylog.writeIntoFile(mLogging.toString());// Schreibe in
						// Logdatei

						shouldUpdate("Spiel zu Ende: Sieger: "
								+ ruler.siegerString());
						return 0;
					}
					illigalCount = 0;
					mBoard.nextPlayer();
					shouldUpdate("An der Reihe:"
							+ mBoard.getName(mBoard.getWhoseTurn()));
				} else {
					shouldUpdate("Dieser Zug ist nicht erlaubt!" + illigalCount);
					illigalCount++;
					if (illigalCount > 20) {
						if (mBoard.getWhoseTurn()
								&& mBoard.getType(mBoard.getWhoseTurn())) {
							mStrategyPathA = 0;
							kiMode();
							mBoard.setNameA(mKiA.getStrategyName());
							mLogging
									.append("\nACHTUNG: KiA Versuchte zu oft einen Illigalen Zug zu machen, und wurde ersetzt\n");
							illigalCount = 0;
						}
						if (!mBoard.getWhoseTurn()
								&& mBoard.getType(mBoard.getWhoseTurn())) {
							mStrategyPathB = 0;

							kiMode();
							mBoard.setNameB(mKiB.getStrategyName());
							mLogging
									.append("\nACHTUNG: KiB Versuchte zu oft einen Illigalen Zug zu machen, und wurde ersetzt\n");
							illigalCount = 0;
						}

					}
				}

				mBeginning = -1;
				mCount = -1;
				if (!mBoard.getType(mBoard.getWhoseTurn())) {
					return 0;
				}
			}
		}

		return 1;
	}

	// die Ki eine mulde wählen lassen
	private int kiMove(boolean who) {
		int choice = -1;
		long zstVorher;
		long zstNachher;
		zstVorher = System.currentTimeMillis();
		try {

			if (who) {
				if (mKiA == null) {
					choice = emergency.move(mBoard.getPitsA(), mBoard
							.getPitsB(), mBoard.getThinkingTime());
				} else {
					choice = mKiA.move(mBoard.getPitsA(), mBoard.getPitsB(),
							mBoard.getThinkingTime());
				}
				if (choice < 6 && choice > -1) {

				} else {
					error("Ki übergibt falschen int wert");
				}

			} else {
				if (mKiB == null) {
					choice = emergency.move(mBoard.getPitsB(), mBoard
							.getPitsA(), mBoard.getThinkingTime());
				} else {
					choice = mKiB.move(mBoard.getPitsB(), mBoard.getPitsA(),
							mBoard.getThinkingTime());
				}
				choice = choice + 6;
				if (!(choice > 5) && !(choice < 12)) {
					error("Ki übergibt falschen int wert");
				}
			}
		} catch (Exception o) {
			System.out.println("Exception: " + o.getMessage());
			if (who) {
				mKiA = null;
				choice = emergency.move(mBoard.getPitsA(), mBoard.getPitsB(),
						mBoard.getThinkingTime());
				mKiA = (MoveStrategy) StrategyHandler.getStrategyHandler()
						.getStrategyByPathIndex(0);
				mBoard.setNameA(mKiA.getStrategyName());
			} else {
				mKiB = null;
				choice = emergency.move(mBoard.getPitsB(), mBoard.getPitsA(),
						mBoard.getThinkingTime());
				mKiB = (MoveStrategy) StrategyHandler.getStrategyHandler()
						.getStrategyByPathIndex(0);
				mBoard.setNameB(mKiB.getStrategyName());
			}
		} catch (Error e) {
			System.out.println("Error: " + e.getMessage());
			if (who) {
				mKiA = null;
				choice = emergency.move(mBoard.getPitsA(), mBoard.getPitsB(),
						mBoard.getThinkingTime());
				mKiA = (MoveStrategy) StrategyHandler.getStrategyHandler()
						.getStrategyByPathIndex(0);
				mBoard.setNameA(mKiA.getStrategyName());
			} else {
				mKiB = null;
				choice = emergency.move(mBoard.getPitsB(), mBoard.getPitsA(),
						mBoard.getThinkingTime());
				mKiB = (MoveStrategy) StrategyHandler.getStrategyHandler()
						.getStrategyByPathIndex(0);
				mBoard.setNameB(mKiB.getStrategyName());
			}
		}
		zstNachher = System.currentTimeMillis();
		System.out.println("Zeit benötigt: " + ((zstNachher - zstVorher))
				+ " milli Sekunden");
		lastThinktime = (zstNachher - zstVorher);
		if (lastThinktime > mBoard.getThinkingTime()) {
			this.shouldUpdate("ACHTUNG, Denkzeit überschritten: "
					+ lastThinktime + " milli Sekunden");
			mLogging.append("\nACHTUNG, Denkzeit überschritten: "
					+ lastThinktime + " milli Sekunden");
		} else {
			mLogging.append("\nKi hat Zug gemacht, Denkzeit: " + lastThinktime
					+ " milli Sekunden");
			this.shouldUpdate("Ki hat Zug gemacht, Denkzeit: " + lastThinktime
					+ " milli Sekunden");
		}
		return choice;
	}

	/*
	 * updated by Shanmugaesan on 05.12.08 setStragyname() added
	 */
	public void setStrategyPathA(int pathA) {
		this.mStrategyPathA = pathA;
		kiMode();
		if (mBoard.getTypeA()) {
			mBoard.setNameA(mKiA.getStrategyName());
		}

	}

	public void setStrategyPathB(int pathB) {
		this.mStrategyPathB = pathB;
		kiMode();
		if (mBoard.getTypeB()) {
			mBoard.setNameB(mKiB.getStrategyName());
		}
	}

	String toLogString(boolean who, int muldenid_log, int muldenanzahl_log) {
		Date datum = new Date();
		SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss dd-MM-yy");
		muldenid_log += 1; // wegen ArrayIndex
		if (!who) {
			muldenid_log = muldenid_log - 6;
		}
		return df.format(datum) + " =>" + " ZugNr : " + (mBoard.getTurnCount())
				+ " " + mBoard.getName(who) + " zog " + muldenid_log
				+ ".Mulde mit " + muldenanzahl_log + " Steinen. "
				+ "Gewinnmuldestatus : " + mBoard.getWinPit(who);
	}

	void shouldUpdate(String s) {
		super.setChanged();
		super.notifyObservers("ZugNr: " + mBoard.getTurnCount() + " " + s);
	}

	/* **************************** */

	// Controller Methoden
	public void setNameA(String s) {
		mBoard.setNameA(s);
	}

	public void setNameB(String s) {
		mBoard.setNameB(s);
	}

	public void setName(String a, String b) {
		mBoard.setNameA(a);
		mBoard.setNameB(b);
	}

	public void setTypeA(boolean in) {
		// false Mensch , true KI
		mBoard.setTypeA(in);
	}

	public void setTypeB(boolean in) {
		// false Mensch , true KI
		mBoard.setTypeB(in);
	}

	public void setWhoseTurn(boolean b) {
		mBoard.setWhoseTurn(b);
	}

	public boolean getTypeA() {
		return mBoard.getTypeA();
	}

	public boolean getTypeB() {
		return mBoard.getTypeB();
	}

	public int[] getBoardPits() {
		int[] arr1 = mBoard.getPitsA();
		int[] arr2 = mBoard.getPitsB();
		int[] arr = GeneralStatics.connectArray(arr1, arr2);
		return arr;
	}

	public int getWinPitA() {
		// TODO Auto-generated method stub
		return mBoard.getWinPitA();
	}

	public int getWinPitB() {
		// TODO Auto-generated method stub
		return mBoard.getWinPitB();
	}

	public String getNameA() {
		return mBoard.getNameA();
	}

	public String getNameB() {
		return mBoard.getNameB();
	}

	public Board getBoard() {
		return this.mBoard;
	}

	public boolean getWhoesTurn() {
		return mBoard.getWhoseTurn();
	}

	public int[] getPitsA() {
		return mBoard.getPitsA();
	}

	public int[] getPitsB() {
		return mBoard.getPitsB();
	}

	public boolean isRunning() {
		return mBoard.isStillrunning();
	}

	public void setUpdate(boolean b) {
		mBoard.setUpdate(b);
	}

	@SuppressWarnings("unused")
	private void setBoard(Board brett) {
		mBoard = brett;
	}

	public String getKiAName() {
		System.out.println("KI A " + mKiA.getStrategyName());
		return mKiA.getStrategyName();
	}

	public String getKiBName() {
		System.out.println("KI B " + mKiB.getStrategyName());
		return mKiB.getStrategyName();
	}

	public int getBeginning() {
		return mBeginning;
	}

	public int getCount() {
		return mCount;
	}

	public int getPit(int in) {
		return mBoard.getPit(in);
	}

	public String getLog() {
		// TODO Auto-generated method stub
		return mLogging.toString();
	}

	public double getVersion() {
		return version;
	}

	public void stopGame() {
		mBoard.setStillrunning(false);
	}

	public void startGame() {
		mBoard.setStillrunning(true);
	}
}
